package com.hapzxb.thread.future2callback;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @author ddd
 * @date 2022-12-03 15:13
 * <p>
 * <p>
 * java.util.concurrent Class CompletableFuture<T> java.lang.Object java.util.concurrent.CompletableFuture<T> All
 * Implemented Interfaces: CompletionStage <T>， Future <T>
 * <p>
 * public class CompletableFuture<T> extends Object implements Future<T>, CompletionStage<T>
 * 甲Future可以明确地完成（设定其值和状态），并且可以被用作CompletionStage ，支持有关的功能和它的完成时触发动作。 当两个或多个线程试图complete ， completeExceptionally
 * ，或cancel一个CompletableFuture，只有一个成功。
 * <p>
 * 除了直接操作状态和结果的这些和相关方法外，CompletableFuture还实现了接口CompletionStage ，具有以下策略：
 * <p>
 * 为异步方法的依赖完成提供的操作可以由完成当前CompletableFuture的线程或完成方法的任何其他调用者执行。 所有不使用显式Executor参数的异步方法都使用ForkJoinPool.commonPool()执行
 * （除非它不支持至少两个并行级别，在这种情况下，使用新的线程）。 为了简化监视，调试和跟踪，所有生成的异步任务都是标记接口CompletableFuture.AsynchronousCompletionTask的实例 。
 * 所有CompletionStage方法都是独立于其他公共方法实现的，因此一个方法的行为不会受到子类中其他方法的覆盖的影响。 CompletableFuture还实施Future ，具有以下政策：
 * <p>
 * 由于（不同于FutureTask ），这个类不能直接控制导致其完成的计算，所以取消被视为另一种形式的异常完成。 方法cancel具有相同的效果completeExceptionally(new
 * CancellationException()) 。 方法isCompletedExceptionally()可用于确定CompletableFuture是否以任何特殊方式完成。
 * 如果使用CompletionException异常完成，方法get()和get(long, TimeUnit)将抛出与对应的CompletionException中保持的相同原因的ExecutionException。
 * 为了简化大多数情况下的使用，此类还定义了方法join()和getNow(T) ，而是在这些情况下直接抛出CompletionException。
 */
public class CompletableFutureDemo2 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        voidTask();
//        testThenCombine();

        CompletableFuture<Integer> thenCombineResult = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "---come in 1");
            return 10;
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "---come in 2");
            return 20;
        }), (x, y) -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "---come in 3");
            return x + y;
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "---come in 4");
            return 30;
        }), (a, b) -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "---come in 5");
            return a + b;
        });
        System.out.println("-----主线程结束，END");
        System.out.println(thenCombineResult.get());

        // 主线程不要立刻结束，否则CompletableFuture默认使用的线程池会立刻关闭:
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    private static void testThenCombine() throws InterruptedException, ExecutionException {
        CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "---come in ");
            return 10;
        });

        CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "---come in ");
            return 20;
        });

        CompletableFuture<Integer> thenCombineResult = completableFuture1.thenCombine(completableFuture2, (x, y) -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "---come in ");
            return x + y;
        });

        System.out.println(thenCombineResult.get());
    }

    private static void voidTask() throws InterruptedException, ExecutionException {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "-----come in");
            //暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("-----task is over");
        });
        System.out.println(future.get());
        System.out.println(Thread.currentThread().getName());
    }
}
